package com.gsafety.wellsfort.controller.organization;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.gsafety.wellsfort.annotation.CheckToken;
import com.gsafety.wellsfort.common.constant.IConstant;
import com.gsafety.wellsfort.common.context.LoginContext;
import com.gsafety.wellsfort.common.context.LoginContextUtil;
import com.gsafety.wellsfort.common.enums.*;
import com.gsafety.wellsfort.common.util.*;
import com.gsafety.wellsfort.config.CacheManager;
import com.gsafety.wellsfort.dao.organization.StudentLoginRelDAO;
import com.gsafety.wellsfort.domain.model.organization.School;
import com.gsafety.wellsfort.domain.model.organization.Student;
import com.gsafety.wellsfort.domain.model.organization.StudentLoginRel;
import com.gsafety.wellsfort.domain.model.security.Admin;
import com.gsafety.wellsfort.domain.model.security.UserLogin;
import com.gsafety.wellsfort.domain.vo.*;
import com.gsafety.wellsfort.domain.vo.security.AccountVO;
import com.gsafety.wellsfort.domain.vo.security.LoginAdminVO;
import com.gsafety.wellsfort.domain.vo.security.LoginVO;
import com.gsafety.wellsfort.service.organization.IStudentService;
import com.gsafety.wellsfort.service.security.IAdminService;
import com.gsafety.wellsfort.service.security.IUserLoginService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.util.*;

@Api(description = "用户接口")
@RestController
@Slf4j
@RequestMapping("/api/customer")
public class UserController {

    @Autowired
    private IUserLoginService userLoginService;
    @Autowired
    private CacheManager cacheManager;

    @Autowired
    private IStudentService studentService;
    @Autowired
    private IAdminService adminService;

    @Autowired
    private StudentLoginRelDAO studentLoginRelDAO;


    /**
     * 检验登录,后台与APP共用登录逻辑
     * APP端登录:
     * (1)手机号+手机验证码免密码登录,无需注册
     * (2)手机号+密码登录,需要先注册
     * (3)第三方合作登录,登录后需要绑定手机号
     * <p>
     * 后台登录逻辑:
     * 账号+密码+图形验证码登录
     *
     * @param loginVO
     * @return
     */
    @ApiOperation(value = "登录校验")
    @CheckToken(value = false)
    @PostMapping("/checkLogin")
    public ApiResponse checkLogin(@RequestBody LoginVO loginVO) {
        UserLogin userLogin = null;
        if (StringUtils.isEmpty(loginVO.getAccount()) || XssJudgeUtils.isSqlInject(loginVO.getAccount())) {
            return ApiResponse.error(ResultCode.USER_LOGIN_FAIL);
        }
        if (StringUtils.isNotEmpty(loginVO.getToken())) {
            //后台登录使用图形验证码登录,必须要传递token
            String captcha = cacheManager.get(loginVO.getToken());
            if (StringUtils.isEmpty(captcha) || !captcha.equalsIgnoreCase(loginVO.getCaptcha())) {
                return ApiResponse.error(ResultCode.IMG_CAPTCHA_IS_ERROR);
            }
            //清除缓存
            cacheManager.remove(loginVO.getToken());
        } else {
            //APP端登录不需要传递token
            if (StringUtils.isNotEmpty(loginVO.getCaptcha())) {
                //使用短信验证码登录,短信验证码登录采用免注册登录
                String captcha = cacheManager.get(RedisPrefixEnum.SMS_CAPTCHA_PREFIX.getPrefix() + loginVO.getAccount());
                if (StringUtils.isEmpty(captcha) || !captcha.equalsIgnoreCase(loginVO.getCaptcha())) {
                    return ApiResponse.error(ResultCode.CAPTCHA_ERROR);
                }
                cacheManager.remove(RedisPrefixEnum.SMS_CAPTCHA_PREFIX.getPrefix() + loginVO.getAccount());
                userLogin = userLoginService.getUserLoginByAccount(loginVO.getAccount());
                if (userLogin == null) {
                    //免注册登录,直接注册登录(密码设置为空,只能免注册登录，不允许账号密码登录)
                    UserLogin userLoginDO = UserLogin.builder().account(loginVO.getAccount()).password(null).
                            originalPassword(null).type(UserTypeEnum.APP.getCode().byteValue()).status(StatusEnum.ENABLE.getValue().byteValue()).
                            creator(IConstant.SYSTEM_OPERATOR).operator(IConstant.SYSTEM_OPERATOR).created(new Date()).modified(new Date()).build();
                    if (userLoginService.add(userLoginDO)) {
                        // 成功登录
                        UserLogin newUserLogin = userLoginService.getUserLoginByAccount(loginVO.getAccount());
                        JSONObject result = loginSuccess(newUserLogin);
                        return ApiResponse.success(result, "success");
                    } else {
                        return ApiResponse.error(ResultCode.ERROR.getCode(), "免注册登录失败!");
                    }
                } else {
                    //验证状态即可,验证会员是否被关停
                    if (userLogin.getStatus().equals(StatusEnum.DISABLE.getValue())) {
                        return ApiResponse.error(ResultCode.USER_LOGIN_STOP);
                    }
                    JSONObject result = loginSuccess(userLogin);
                    return ApiResponse.success(result, "success");
                }
            }
        }
        if (userLogin == null) {
            userLogin = userLoginService.getUserLoginByAccount(loginVO.getAccount());
        }
        // //验证用户名或者手机号
        if (userLogin == null) {
            return ApiResponse.error(ResultCode.USER_LOGIN_FAIL);
        }
        // 验证密码
        if (!DigestUtils.md5Hex(loginVO.getPassword()).equals(userLogin.getPassword())) {
            return ApiResponse.error(ResultCode.USER_LOGIN_FAIL);
        }
        // 验证会员是否被关停
        if (userLogin.getStatus().equals(StatusEnum.DISABLE.getValue().byteValue())) {
            return ApiResponse.error(ResultCode.USER_LOGIN_STOP);
        }
        Admin admin = adminService.getByLoginId(userLogin.getId());
        if (admin != null && admin.getStatus().equals(StatusEnum.DISABLE.getValue().byteValue())) {
            return ApiResponse.error(ResultCode.USER_LOGIN_STOP);
        }
        JSONObject result = loginSuccess(userLogin);
        return ApiResponse.success(result, "success");
    }

    /**
     * @return
     */
    private JSONObject loginSuccess(UserLogin userLogin) {
        JSONObject result = new JSONObject();
        // 成功登录
        String token = JwtUtil.createJWT(8 * 60 * 60 * 1000, userLogin);
        //token ip添加进入缓存
        cacheManager.setHashKey(RedisPrefixEnum.ACCOUNT_TOKEN_UNIQUE.getPrefix(), userLogin.getAccount(), token);
        result.put(IConstant.TOKEN, token);
        //是否绑定学生,提供给APP端使用
        Student student = studentService.getByLoginId(userLogin.getId());
        if (student != null) {
            result.put("checkBind", true);
        } else {
            //游客模式,添加虚拟学生
            Student stu = studentService.getAllByLoginId(userLogin.getId());
            if (stu == null) {
                Student studentDo = new Student();
                studentDo.setSchoolId(SchoolEnum.FICTITIOUS_SCHOOL.value);
                studentDo.setClassId(ClassEnum.FICTITIOUS_CLASS.value);
                studentDo.setName(userLogin.getAccount());
                studentDo.setCreator("system");
                studentDo.setOperator("system");
                studentDo.setParentName(userLogin.getAccount());
                studentDo.setParentPhone(userLogin.getAccount());
                //虚拟学生标识
                studentDo.setExt1("0");
                studentService.addStudent(studentDo);
                StudentLoginRel studentLoginRel = new StudentLoginRel();
                studentLoginRel.setLoginId(userLogin.getId());
                studentLoginRel.setStudentId(studentDo.getId());
                studentLoginRel.setCreated(new Date());
                studentLoginRel.setModified(new Date());
                studentLoginRelDAO.insertSelective(studentLoginRel);
            }
        }
        return result;
    }

    @ApiOperation(value = "用户注册")
    @CheckToken(value = false)
    @PostMapping("/register")
    public ApiResponse register(@RequestBody AccountVO accountVO) {
        //验证码校验
        String captcha = cacheManager.get(RedisPrefixEnum.SMS_CAPTCHA_PREFIX.getPrefix() + accountVO.getPhone());
        if (StringUtils.isEmpty(accountVO.getCaptcha()) || !Objects.equals(captcha, accountVO.getCaptcha())) {
            return ApiResponse.error(ResultCode.CAPTCHA_ERROR);
        }
        //清除缓存
        cacheManager.remove(RedisPrefixEnum.SMS_CAPTCHA_PREFIX.getPrefix() + accountVO.getPhone());
        //判断用户名是否存在
        UserLogin userLogin = userLoginService.getUserLoginByAccount(accountVO.getPhone());
        if (userLogin != null) {
            return ApiResponse.error(ResultCode.PHONE_IS_EXIST);
        }
        UserLogin userLoginDO = UserLogin.builder().account(accountVO.getPhone()).password(DigestUtils.md5Hex(accountVO.getPassword())).
                originalPassword(accountVO.getPassword()).type(UserTypeEnum.APP.getCode().byteValue()).creator("system").operator("system").
                created(new Date()).modified(new Date()).build();
        if (userLoginService.add(userLoginDO)) {
            return ApiResponse.success("注册成功");
        } else {
            return ApiResponse.error(ResultCode.ERROR, "注册失败");
        }
    }

    @ApiOperation(value = "用户绑定")
    @PostMapping("/bind")
    public ApiResponse bind(@RequestBody BindVO bindVO) {
        if (bindVO.getSchoolId() == null || bindVO.getClassId() == null) {
            return ApiResponse.error(ResultCode.ERROR, "关联学校或者班级为空!");
        }
        StudentQueryVO query = new StudentQueryVO();
        query.setPageNo(1);
        query.setPageSize(50);
        query.setSchoolId(bindVO.getSchoolId());
        query.setClassId(bindVO.getClassId());
        query.setExt1("1");
        //name 是模糊查询的,需要精确匹配一波
        query.setName(bindVO.getName());
        ApiResponse<List<StudentResultVO>> apiResponse = studentService.list(query);
        if (apiResponse.getCode() == ResultCode.SUCCESS.getCode() && apiResponse.getData() != null && apiResponse.getData().size() > 0) {
            List<StudentResultVO> list = apiResponse.getData();
            for (StudentResultVO student : list) {
                if (student.getName().equals(bindVO.getName())) {
                    //清除虚拟绑定
                    studentLoginRelDAO.deleteByLoginId(LoginContextUtil.getUid());
                    //更新学生关联登录表
                    Integer insert = studentService.bindAccount(student.getId(), LoginContextUtil.getUid());
                    if (insert > 0) {
                        //更新虚拟学生 ext2属性为登录用户id,做历史记录留存
                        Student oldStudent = LoginContextUtil.getStudent();
                        if (oldStudent != null) {
                            StudentVO studentVo = new StudentVO();
                            studentVo.setId(oldStudent.getId());
                            studentVo.setExt2(String.valueOf(LoginContextUtil.getUid()));
                            studentService.update(studentVo);
                        }
                        return ApiResponse.success("绑定成功");
                    }
                }
            }
        }
        return ApiResponse.error(ResultCode.ERROR.getCode(),"请输入正确的信息");
    }

    @ApiOperation(value = "用户解除绑定")
    @PostMapping("/unbind")
    public ApiResponse unbind() {
        //更新学生表
        if (studentService.unBindAccount(LoginContextUtil.getUid()) > 0) {
            //用户解绑
            userLoginService.unBindInfo(LoginContextUtil.getUid());
            //查找以前绑定虚拟学生,添加虚拟绑定
            List<Student> list = studentService.selectByExt2(String.valueOf(LoginContextUtil.getUid()));
            if (list != null && list.size() > 0) {
                log.info("list={}", JSON.toJSONString(list));
                Student student = list.get(0);
                student.setExt2(null);
                //清除ext2
                studentService.updateSetExt2(student);
                StudentLoginRel studentLoginRel = new StudentLoginRel();
                studentLoginRel.setLoginId(LoginContextUtil.getUid());
                studentLoginRel.setStudentId(student.getId());
                studentLoginRel.setCreated(new Date());
                studentLoginRel.setModified(new Date());
                studentLoginRelDAO.insertSelective(studentLoginRel);
                return ApiResponse.success("解除绑定成功");
            }
        }
        return ApiResponse.error();
    }

    @ApiOperation(value = "修改密码")
    @PostMapping("/modifyPassword")
    public ApiResponse modifyPassword(@RequestBody LoginVO loginVO) {
        String captcha = cacheManager.get(RedisPrefixEnum.SMS_CAPTCHA_PREFIX.getPrefix() + loginVO.getAccount());
        if (StringUtils.isEmpty(captcha) || !captcha.equalsIgnoreCase(loginVO.getCaptcha())) {
            return ApiResponse.error(ResultCode.CAPTCHA_ERROR);
        }
        //手动清除缓存
        cacheManager.remove(RedisPrefixEnum.SMS_CAPTCHA_PREFIX.getPrefix() + loginVO.getAccount());
        if (StringUtils.isEmpty(loginVO.getPassword())) {
            return ApiResponse.error(ResultCode.ERROR, "新密码不能为空!");
        }
        //校验手机号
        UserLogin userLogin = userLoginService.getUserLoginById(LoginContextUtil.getUid());
        if (StringUtil.isEmpty(userLogin.getAccount()) || !Objects.equals(userLogin.getAccount(), loginVO.getAccount())) {
            return ApiResponse.error(ResultCode.USER_NOT_HAS_AUTHORITY);
        }
        //更新学生表
        if (userLoginService.modifyPassword(loginVO.getPassword())) {
            return ApiResponse.success("修改密码成功");
        } else {
            return ApiResponse.error();
        }
    }


    /**
     * 业务: 操作ip限制一天3次
     *
     * @param loginVO
     * @param request
     * @return
     */
    @ApiOperation(value = "忘记密码")
    @CheckToken(value = false)
    @PostMapping("/forgetPasswordForAdmin")
    public ApiResponse forgetPasswordForAdmin(@RequestBody LoginAdminVO loginVO, HttpServletRequest request) {
        String phone = null;
        //后台登录使用图形验证码登录,必须要传递token
        String captcha = cacheManager.get(loginVO.getToken());
        if (StringUtils.isEmpty(captcha) || !captcha.equalsIgnoreCase(loginVO.getCaptcha())) {
            return ApiResponse.error(ResultCode.IMG_CAPTCHA_IS_ERROR);
        }
        cacheManager.remove(loginVO.getToken());
        //管理员忘记密码特殊处理,传递账号转换成手机号
        UserLogin userLogin = userLoginService.getUserLoginByAccount(loginVO.getAccount());
        if (userLogin == null) {
            return ApiResponse.error(ResultCode.INVALID_PARAM);
        }
        Admin admin = adminService.getByLoginId(userLogin.getId());
        if (admin == null) {
            return ApiResponse.error(ResultCode.INVALID_PARAM);
        }
        phone = admin.getPhone();
        String smsCode = cacheManager.get(RedisPrefixEnum.SMS_CAPTCHA_PREFIX.getPrefix() + phone);
        if (StringUtils.isEmpty(smsCode) || !smsCode.equalsIgnoreCase(loginVO.getSmsCode())) {
            return ApiResponse.error(ResultCode.CAPTCHA_ERROR);
        }
        cacheManager.remove(RedisPrefixEnum.SMS_CAPTCHA_PREFIX.getPrefix() + phone);
        String count = cacheManager.get(RedisPrefixEnum.IP_OPERATOR_PREFIX.getPrefix() + DigestUtils.md5Hex(IpUtil.getIp(request)));
        if (count == null) {
            cacheManager.set(RedisPrefixEnum.IP_OPERATOR_PREFIX.getPrefix() + DigestUtils.md5Hex(IpUtil.getIp(request)), new String("1"), RedisPrefixEnum.IP_OPERATOR_PREFIX.getExpireTime());
        } else {
            if (Integer.parseInt(count) > 3) {
                return ApiResponse.error(ResultCode.IP_OPERATOR_FREQUENTLY);
            } else {
                cacheManager.set(RedisPrefixEnum.IP_OPERATOR_PREFIX.getPrefix() + DigestUtils.md5Hex(IpUtil.getIp(request)), String.valueOf(Integer.parseInt(count) + 1), RedisPrefixEnum.IP_OPERATOR_PREFIX.getExpireTime());
            }
        }
        if (StringUtils.isEmpty(loginVO.getPassword())) {
            return ApiResponse.error(ResultCode.ERROR, "新密码不能为空!");
        }
        UserLogin newUserLogin = UserLogin.builder().id(userLogin.getId()).
                password(DigestUtils.md5Hex(loginVO.getPassword())).
                originalPassword(loginVO.getPassword()).operator(loginVO.getAccount()).build();
        //更新登录信息
        if (userLoginService.update(newUserLogin) > 0) {
            return ApiResponse.success("修改密码成功");
        } else {
            return ApiResponse.error();
        }
    }


    @ApiOperation(value = "获取用户详情")
    @PostMapping("/detail")
    public ApiResponse<UserVO> detail() {
        return ApiResponse.success(userLoginService.getDetail());
    }


    /**
     * 退出登录
     */
    @PostMapping(value = "/logout")
    public ApiResponse logOut(HttpServletRequest request) {
        Integer uid = LoginContextUtil.getUid();
        log.info("uid={},时间={},退出登录", uid, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
        /**登陆来源是移动端 注销需要清空用户表设备信息**/
        if (LoginContextUtil.getUserBo().getType().equals(IConstant.LOGIN_TYPE)) {
            userLoginService.unBindInfo(uid);
        }
        //清除redis缓存token
        Map<String, String> accountMap = (Map) cacheManager.getHash(RedisPrefixEnum.ACCOUNT_TOKEN_UNIQUE.getPrefix());
        if (accountMap != null) {
            String token = request.getHeader(IConstant.TOKEN);
            accountMap.remove(token);
            cacheManager.set(RedisPrefixEnum.ACCOUNT_TOKEN_UNIQUE.getPrefix(), accountMap);
        }
        return ApiResponse.success();
    }

    /**
     * 业务: 操作ip限制一天3次
     *
     * @param loginVO
     * @param request
     * @return
     */
    @ApiOperation(value = "忘记密码")
    @CheckToken(value = false)
    @PostMapping("/forgetPassword")
    public ApiResponse forgetPassword(@RequestBody LoginVO loginVO, HttpServletRequest request) {
        String captcha = cacheManager.get(RedisPrefixEnum.SMS_CAPTCHA_PREFIX.getPrefix() + loginVO.getAccount());
        if (StringUtils.isEmpty(captcha) || !captcha.equalsIgnoreCase(loginVO.getCaptcha())) {
            return ApiResponse.error(ResultCode.CAPTCHA_ERROR);
        }
        cacheManager.remove(RedisPrefixEnum.SMS_CAPTCHA_PREFIX.getPrefix() + loginVO.getAccount());
        String count = cacheManager.get(RedisPrefixEnum.IP_OPERATOR_PREFIX.getPrefix() + DigestUtils.md5Hex(IpUtil.getIp(request)));
        if (count == null) {
            cacheManager.set(RedisPrefixEnum.IP_OPERATOR_PREFIX.getPrefix() + DigestUtils.md5Hex(IpUtil.getIp(request)), new String("1"), RedisPrefixEnum.IP_OPERATOR_PREFIX.getExpireTime());
        } else {
            if (Integer.parseInt(count) > 3) {
                return ApiResponse.error(ResultCode.IP_OPERATOR_FREQUENTLY);
            } else {
                cacheManager.set(RedisPrefixEnum.IP_OPERATOR_PREFIX.getPrefix() + DigestUtils.md5Hex(IpUtil.getIp(request)), String.valueOf(Integer.parseInt(count) + 1), RedisPrefixEnum.IP_OPERATOR_PREFIX.getExpireTime());
            }
        }
        if (StringUtils.isEmpty(loginVO.getPassword())) {
            return ApiResponse.error(ResultCode.ERROR, "新密码不能为空!");
        }
        UserLogin userLogin = userLoginService.getUserLoginByAccount(loginVO.getAccount());
        if (userLogin == null) {
            return ApiResponse.error(ResultCode.INVALID_PARAM);
        }
        UserLogin newUserLogin = UserLogin.builder().id(userLogin.getId()).
                password(DigestUtils.md5Hex(loginVO.getPassword())).
                originalPassword(loginVO.getPassword()).operator(loginVO.getAccount()).build();
        //更新登录信息
        if (userLoginService.update(newUserLogin) > 0) {
            return ApiResponse.success("修改密码成功");
        } else {
            return ApiResponse.error();
        }
    }

}

